package com.hqd.jjvm.jnative.lang;

import com.hqd.jjvm.jnative.JNativeRegistry;
import com.hqd.jjvm.rtda.JThread;
import com.hqd.jjvm.rtda.heap.JClass;
import com.hqd.jjvm.rtda.obj.JObject;

import java.io.IOException;

public class JObjectNativeRegistry extends JNativeRegistry {
    private static final JObjectNativeRegistry instance = new JObjectNativeRegistry();
    protected static final String CLASS_PATH = "java/lang/Object";

    static {
        registry(CLASS_PATH, "registerNatives", "()V", JNativeRegistry::registerNatives);
        registry(CLASS_PATH, "hashCode", "()I", JObjectNativeRegistry::hashCode0);
        registry(CLASS_PATH, "getClass", "()Ljava/lang/Class;", JObjectNativeRegistry::getClass0);
        registry(CLASS_PATH, "clone", "()Ljava/lang/Object;", JObjectNativeRegistry::clone0);
        registry(CLASS_PATH, "notifyAll", "()V", JObjectNativeRegistry::notifyAll0);
    }

    private static void notifyAll0(JThread jThread) {
    }

    private static void clone0(JThread jThread) {
        JObject jObject = jThread.getJvmStack().getLocalVarsRefVal(0);
        try {
            JClass jc = jObject.getJClass().getLoader().loadJClass(Cloneable.class.getName());
            if (JClass.isImplements(jObject.getJClass(), jc)) {
                throw new CloneNotSupportedException(jObject.getJClass().getClassName() + " is not implements " + jc.getClassName());
            }
            jThread.getJvmStack().pushOperandStackRefVal(jObject.clone());
        } catch (ClassNotFoundException | CloneNotSupportedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void getClass0(JThread jThread) {
        JObject thisObj = jThread.getJvmStack().getTop().getLocalVars().getRefVal(0);
        jThread.getJvmStack().getTop().pushRef(thisObj.getJClass().getJObject());
    }

    protected static void hashCode0(JThread jThread) {
        int hashCode = jThread.getJvmStack().getLocalVarsRefVal(0).getData().hashCode();
        jThread.getJvmStack().pushOperandStackIntVal(hashCode);
    }

    public static JObjectNativeRegistry getInstance() {
        return instance;
    }
}
